#include "hypersphere.h"


// assumes *solution is NR array
Hypersphere::Hypersphere(int numDimension, double *solution, double radius) : m_solution(numDimension)
{
  m_radius = radius;

  // copy content of solution to m_solution
  for (int i = 1; i <= numDimension; i++)
  {
    m_solution[i-1] = solution[i];
  }
}

// vector version of constructor
Hypersphere::Hypersphere(const vector<double> &solution, double radius) 
{
  m_solution = solution;
  m_radius = radius;
}


// reason for this function is to avoid having to create new hypersphere objects
// continuous as you are changed the tabulist or otherwise.
// this allows you to 'reuse' the object
void Hypersphere::setRegion(int numDimension, double *solution, double radius)
{
  if (m_solution.size() == 0) 
  {
    m_solution.resize(numDimension);
  }

  m_radius = radius;

  // copy content of solution to m_solution
  for (int i = 1; i <= numDimension; i++)
  {
    m_solution[i-1] = solution[i];
  }
}

void Hypersphere::setRegion(int numDimension, double *solution, double radius, double funcval)
{
  if (m_solution.size() == 0) 
  {
    m_solution.resize(numDimension);
  }

  m_radius = radius;
  m_funcval = funcval;

  // copy content of solution to m_solution
  for (int i = 1; i <= numDimension; i++)
  {
    m_solution[i-1] = solution[i];
  }
}

// here assumes that memory for m_solution already there and also that its size
// is the same as the dimension of solution
void Hypersphere::setRegion(double *solution, double radius)
{
  m_radius = radius;

  // copy content of solution to m_solution
  for (unsigned int i = 1; i <= m_solution.size(); i++)
  {
    m_solution[i-1] = solution[i];
  }
}

// vector version
void Hypersphere::setRegion(const vector<double> &solution, double radius)
{
  // copies the radius and the coordinates of the solution
  m_radius = radius;
  m_solution = solution;
}

// here assume that dimension of solution is the same as dimension of
// m_solution
bool Hypersphere::isInRegion(double *solution)
{
  // find the distance between solution and m_solution
  double distanceSqr = 0.0;
  double rad = m_radius*m_radius;

  for (unsigned int i = 0; i < m_solution.size(); i++)
  {
    distanceSqr += (m_solution[i]-solution[i+1])*(m_solution[i]-solution[i+1]);
  }

  if ( distanceSqr <= rad)
  {
    return true;
  }
  else
  {
    return false;
  }
}

// vector version
bool Hypersphere::isInRegion(const vector<double> &solution)
{
  // find the distance between solution and m_solution
  double distanceSqr = 0.0;
  double rad = m_radius*m_radius;

  for (unsigned int i = 0; i < m_solution.size(); i++)
  {
    distanceSqr += (m_solution[i]-solution[i])*(m_solution[i]-solution[i]);
  }

  // if the new solution is inside the radius of the hyersphere
  // centered around the old solution then the new solution is
  // inside the hypersphere of the old solution
  if ( distanceSqr <= rad)
  {
    return true;
  }
  else
  {
    return false;
  }
}

// used to test it is working
void Hypersphere::test()
{
   Hypersphere testSphere;

   cout << "This is a test of the Hypersphere class\n";

   vector<double> d;
   d.push_back(2.1);
   d.push_back(4.1);

   testSphere.setRegion(d, 3.0);

   cout << "Is point in region " << testSphere.isInRegion(d) << endl;

   d[0] = 30.1;

   cout << "Is point in region " << testSphere.isInRegion(d) << endl;
}


